/***************************************************************
*  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
*  All rights reserved.
*
*  This file is part of the GroupMe! Project. Source code of 
*  this project is closed and redistribution of this code is
*  prohibited. 
*  
*  Contact: http://www.groupme.net
*
*  This copyright notice MUST APPEAR in all copies of the file!
***************************************************************/
package net.groupme.controller.ajax;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import net.groupme.controller.model.GroupBean;
import net.groupme.controller.model.HtmlFormattedElement;
import net.groupme.controller.model.ResourceVisualizationBean;
import net.groupme.controller.model.SearchResult;
import net.groupme.controller.model.UserForm;
import net.groupme.exceptions.GroupVisualizationException;
import net.groupme.exceptions.search.SearchEngineException;
import net.groupme.gui.constants.VIEW_VOCABULARY;
import net.groupme.gui.rendering.BigResourceRenderingUtility;
import net.groupme.gui.rendering.GroupRenderer;
import net.groupme.gui.rendering.RssRenderer;
import net.groupme.model.Group;
import net.groupme.model.MODEL_CONSTANTS;
import net.groupme.model.ObjectFactory;
import net.groupme.model.Resource;
import net.groupme.model.ResourceVisualization;
import net.groupme.model.Tag;
import net.groupme.model.User;
import net.groupme.model.dao.DATABASE_CONSTANTS;
import net.groupme.search.SearchManager;
import net.groupme.utils.StringUtilities;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

//
/**
 * created on 09.07.2007
 * 
 * This Ajax controller manages the browsing of groups.
 * 
 * @author Mischa Frank, <a href="mailto:code@planetfrank.net">code@planetfrank.net</a>
 * @author last edited by: $Author: fabian $
 * 
 * @version $Revision: 1.28 $ $Date: 2009-06-12 05:41:26 $
 */
public class GroupBrowsingAjaxController implements ApplicationContextAware {

	/** Logger for this class and subclasses */
	protected final Log logger = LogFactory.getLog(getClass());
	
	/** the Spring application context */
	private ApplicationContext applicationContext = null;
	
	/* (non-Javadoc)
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		this.applicationContext = context;
	}
	
	@SuppressWarnings("unchecked")
	public String getAllGroups() {
		String html = "";
		try {
			Statement sqlStatement = null;
			ResultSet loggingTable = null;
			sqlStatement = ObjectFactory.ds.getConnection().createStatement();
			loggingTable = sqlStatement
					.executeQuery("SELECT DISTINCT id, name, description FROM "+ DATABASE_CONSTANTS.TABLE_RESOURCE 
							+ " RIGHT JOIN " + DATABASE_CONSTANTS.TABLE_GROUPRESOURCE + " ON " 
							+ DATABASE_CONSTANTS.RESOURCE_ID + " = " + DATABASE_CONSTANTS.GROUPRESOURCE_GROUP_ID 
							+ " WHERE " +  DATABASE_CONSTANTS.RESOURCE_TYPE + " = '" + MODEL_CONSTANTS.RESOURCE_TYPE_GROUP
							+ "' ORDER BY " + DATABASE_CONSTANTS.RESOURCE_NAME);
			while (loggingTable.next()) {
				if (!loggingTable.getString(2).trim().equals("")) {
					html += "<a href=\"" + VIEW_VOCABULARY.RESTful_GROUP_URI_PATTERN 
							+ loggingTable.getString(1)
							+ "\" onfocus=\"if(this.blur)this.blur()\" style=\"font-size:0.7em;\" ";
					html += "title=\"" + loggingTable.getString(3) + "\">"
							+ loggingTable.getString(2) + "</a><br/>";
				}
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return html;
	}
	

	
	/**
	 * Performs a search for Groups using the given keyword string (could contain multiple keywords).
	 * @param keyword the keyword(s)
	 * @param engineIndicator a String indicating which search engine to be used
	 * @return array containing search results ({@link SearchResult}) or null if the corresponding search engine could not be executed correctly.
	 */
	public String searchForGroups(String keywords){
		//reset actual search result:
		String resultHTML = "No Groups found.";
		logger.info("Searching for GroupMe-Groups...");
		SearchManager searchManager = (SearchManager) applicationContext.getBean(VIEW_VOCABULARY.GROUPME_SEARCH_MANGER, SearchManager.class);
		try {
			List<Group> suitingGroups = searchManager.searchForGroups(keywords, false);
			resultHTML = "";
			for(Group element: suitingGroups){
				if ("".equals(element.getName().trim()))
					continue;
				//resultHTML += "<a href=\"#\" style=\"font-size:0.7em;\" onclick=\"loadGroup('" + element.getId() + "')\" ";
				resultHTML += "<a href=\"" + VIEW_VOCABULARY.RESTful_GROUP_URI_PATTERN + element.getId() + "\" onfocus=\"if(this.blur)this.blur()\" style=\"font-size:0.7em;\" ";
				resultHTML += "title=\"" + element.getDescription() + "\">" + element.getName() + "</a><br/>";
			}
		} catch (SearchEngineException e) {
			e.printStackTrace();
			logger.error("An error occured during internal search for groups.", e);
			return "An error occured during Search.";
		}
		return resultHTML;
	}
	
	/**
	 * This method loads all Resources of a Group given by its ID and renders it by a suiting Renderer.
	 * @param groupId the id of the chosen group
	 * @param groupWith the width of the current grouparea
	 * @param groupHeight the height of the current grouparea
	 * @return an Array of the formatted Resources
	 * @throws GroupVisualizationException 
	 * @throws UnsupportedEncodingException 
	 */
	public ResourceVisualizationBean[] loadResources(String groupId, Integer groupWidth, Integer groupHeight) throws GroupVisualizationException, UnsupportedEncodingException{
		logger.info("Load Group with ID: " + groupId);
		Group group = ObjectFactory.getGroup(groupId);
		User defaultUser = group.getUsers("owner").iterator().next();
		ResourceVisualization[] groupResources;
			groupResources = group.getActualGroupVisualization(defaultUser.getId())
														.getResourceVisualizations().toArray(new ResourceVisualization[0]);
			logger.info("# Resources in this group: " + groupResources.length);
//		sortieren nach zAxis
		Arrays.sort(groupResources, new ResourceVisuComparatorZAxis());
//		vorbereiten der Beans		
		ResourceVisualizationBean[] resourceVisualizationBeans = new ResourceVisualizationBean[groupResources.length];
		int zAxis = 10;
		int relativePosX = 0;
		int relativePosY = 0;
		int relativeWidth = 0;
		int relativeHeight = 0;
		for (int i = 0; i < groupResources.length; i++) {
//		Berechnung der relativen Gr��e- und Positionsangaben
			relativePosX = ((groupResources[i].getPositionX()*groupWidth)/1000);
			relativePosY = ((groupResources[i].getPositionY()*groupHeight)/1000);
			relativeWidth = ((groupResources[i].getWidth()*groupWidth)/1000);
			relativeHeight = ((relativeWidth*1000)/groupResources[i].getHeight());
//		Estellung des Tag-Arrays und des Tag-Keyword-Arrays
			List<Tag> tagList = (List) groupResources[i].getResource().getTags(ObjectFactory.getGroup(groupId));
			String[] tagArray = new String[tagList.size()];
			String[] tagKeywordArray = new String[tagList.size()];
			for (int j = 0; j < tagList.size(); j++) {
				String keyword = tagList.get(j).getKeyword();
				String URLkeyword = keyword.replaceAll(" ", "_");	
				URLkeyword = URLEncoder.encode(URLkeyword, "UTF-8");
				
				//tagArray[j] = tagList.get(j).getKeyword();
				tagArray[j] = URLkeyword;
				tagKeywordArray[j] = keyword;
				
			}
//		Erstellung des Beans
			resourceVisualizationBeans[i] = new ResourceVisualizationBean(
					groupResources[i].getResource().getDescription(), 
					groupResources[i].getResource().getId(), 
					groupResources[i].getResource().getName(),
					relativeHeight -23,
					relativeWidth -25,
					relativePosX +1,
					relativePosY -1,
					zAxis,
					groupResources[i].getURI().toString(),
					groupResources[i].getResource().getURL().toString(),
					groupResources[i].getRenderer(),
					tagArray,
					tagKeywordArray
					);
			logger.info("Created ResourceVisualizationBean with parameters: " 
					+ " Description: "+groupResources[i].getResource().getDescription()
					+ " ID: "+groupResources[i].getResource().getId()
					+ " Name: "+groupResources[i].getResource().getName()
					+ " PositionX: "+relativePosX
					+ " PositionY: "+relativePosY
					+ " Width: "+relativeWidth
					+ " Height: "+relativeHeight
					+ " GroupWidth: "+groupWidth
					+ " GroupHeight: "+groupHeight
					+ " z-Axis: "+zAxis
					+ " URI: "+groupResources[i].getURI().toString()
					+ " URL: "+groupResources[i].getResource().getURL().toString()
					+ " Renderer: "+groupResources[i].getRenderer());
			zAxis++;
		}
		return resourceVisualizationBeans;
	}
	
	public ResourceVisualizationBean getRenderedContentForRSSResource(String[] tagArray, String html, String uRL, String uRI, String name, String id){
		RssRenderer renderer = new RssRenderer();
		ResourceVisualizationBean resVisuBean = new ResourceVisualizationBean(
				"", 
				id, 
				"",
				0,
				0,
				0,
				0,
				0,
				uRI,
				uRL,
				"",
				tagArray,
				tagArray
				);
		try {
			resVisuBean.setHtml(html + renderer.renderContentAsHTML(uRL, uRI, name));
			return resVisuBean;
		} catch (MalformedURLException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			resVisuBean.setHtml(html + "The URL of this RSS-Feed is not valid.");
			return resVisuBean;
		}
	}
	
	public ResourceVisualizationBean getRenderedContentForGroupResource(String[] tagArray, String html, String uRL, String uRI, String iD, String name){
		GroupRenderer renderer = new GroupRenderer();
		ResourceVisualizationBean resVisuBean = new ResourceVisualizationBean(
				"", 
				iD, 
				"",
				0,
				0,
				0,
				0,
				0,
				uRI,
				uRL,
				"",
				tagArray,
				tagArray
				);
		try {
			resVisuBean.setHtml(html + renderer.renderContentAsHTML(uRL, uRI, iD, name));
			return resVisuBean;
		} catch (MalformedURLException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			resVisuBean.setHtml(html + "The URL of this RSS-Feed is not valid.");
			return resVisuBean;
		}
	}
	
	
	/**
	 * This method loads tags for the selected group. It also renders the Tags by 
	 * a suiting renderer.
	 * @param allTags  if this parameter is <code>false</code>, then we only search for tags that were
	 * inserted by the actual user, otherwise (if this parameter is <code>true</code>) all tags are
	 * considered.
	 * 
	 * @return an array of the HTML formatted Tags
	 */
	public HtmlFormattedElement[] loadTagsForGroup(String groupID, boolean allTags){
		Group currentGroup = ObjectFactory.getGroup(groupID);
		Tag[] tags = currentGroup.getTags().toArray(new Tag[0]);
		HtmlFormattedElement[] formattedElements = new HtmlFormattedElement[tags.length];
		for (int i = 0; i < tags.length; i++) {
			//TODO Renderer for Tags benutzen, falls erwuenscht
			formattedElements[i] = renderTag(tags[i]);
		}
		return formattedElements;
	}
	
	/**
	 * This method loads all Tags for the given Resource, the User logged in
	 * and the Group that is shown at the moment. It also renders the Tags by 
	 * a suiting renderer.
	 * @param resourceID the ID of the tagged Resource
	 * @return an array of the HTML formatted Tags
	 */
	public HtmlFormattedElement[] loadTagsForResource(String resourceVisuDivID){
		ResourceVisualization resVisu;
		try {
			resVisu = ObjectFactory.getResourceVisualization(StringUtilities.getIdFromURI(new URI(resourceVisuDivID)));
		Resource resource = resVisu.getResource();
		logger.info("loading tags for Resource with ID: " + resource.getId());
		Tag[] tags = ObjectFactory.getResource(resource.getId()).getTags().toArray(new Tag[0]);
		HtmlFormattedElement[] formattedElements = new HtmlFormattedElement[tags.length];
		for (int i = 0; i < tags.length; i++) {
			//TODO Renderer for Tags benutzen, falls erwuenscht
			formattedElements[i] = formattedElements[i] = renderTag(tags[i]);
		}
		return formattedElements;
		} catch (URISyntaxException e) {
			logger.warn("Problems with ID of ResourceVisualization.", e);
			return null;
		}
	}
	
	/**
	 * Returns the detail content for a BRV for a Resource.
	 * @param resourceId the ID of the Resource
	 * @param resVisuURI the URI of the ResourceVisualization
	 * @return the detail content as HTML
	 */
	public String getResourceDetailsView(String resourceId, String resVisuURI){
		return BigResourceRenderingUtility.getResourceDetailsView(resourceId);
	}
	
	/**
	 * Returns max. 3 similar groups for the currently viewed group.
	 * @param groupId the ID of the currently viewed group
	 * @return an array of {@link HtmlFormattedElement}s reprseneting the similar groups
	 */
	public HtmlFormattedElement[] getSimilarGroups(String groupId){
		SearchManager searchManager = (SearchManager) applicationContext.getBean(VIEW_VOCABULARY.GROUPME_SEARCH_MANGER, SearchManager.class);
		List<Group> similars = searchManager.getSimilarGroups(ObjectFactory.getGroup(groupId), 3);
		HtmlFormattedElement[] similarsHTML = new HtmlFormattedElement[similars.size()];
		for (int i = 0; i < similars.size(); i++) {
			Group group = similars.get(i);
			String html = "<a href=\""+ VIEW_VOCABULARY.RESTful_GROUP_URI_PATTERN  + group.getId() + "\""  ;
			html += "title=\"" + group.getDescription() + "\">" + group.getName() + "</a><br/>";
			similarsHTML[i]= new HtmlFormattedElement(i + "", html);
		}
		return similarsHTML;
	}
	
	/**
	 * Returns some details (name, description) about a group.
	 * @param groupId the id of the group
	 * @return a simple group bean (containing name, description)
	 */
	public GroupBean getGroupDetails(String groupId){
		Group group = ObjectFactory.getGroup(groupId);
		logger.info("Group details of: " + group.getName());
		return new GroupBean(groupId, group.getName(), group.getDescription());
	}
	
	/**
	 * Returns some details about the owner of a group (username, first name, lastname, email, foafURL).
	 * @param groupId the id of the group
	 * @return a simple group bean (containing name, description)
	 */
	public UserForm getGroupOwnerDetails(String groupId){
		Group group = ObjectFactory.getGroup(groupId);
		User owner = null;
		Iterator<User> owners = group.getUsers(MODEL_CONSTANTS.ROLE_OWNER).iterator();
		if(owners.hasNext()){
			owner = owners.next();
		}
		return new UserForm(owner.getUserName(), null, owner.getFirstName(), owner.getLastName(), owner.getEmail(), owner.getFoaf(), owner.getPhoto());
	}
	
	/**
	 * Renders a given tag by creating a hyperlink which causes invocation of the internal GroupMe! search engine
	 * (searching for groups and resources).
	 * @param tag the tag to format as HTML
	 * @return HTML-formatted {@link Tag}
	 */
	private HtmlFormattedElement renderTag(Tag tag){
		String tagLink = "<a href=\"" + VIEW_VOCABULARY.GROUPME_BASE_URL + VIEW_VOCABULARY.ACTION_SEARCH + "?" + VIEW_VOCABULARY.PARAMETER_KEYWORD 
			+ "=" + tag.getKeyword() +"\" title=\"Search for Groups and Resources tagged with " + 
			tag.getKeyword() +"\">" + tag.getKeyword() +"</a>";
		return new HtmlFormattedElement(tag.getId(), tagLink);
	}
	
	private class GroupComparatorName implements Comparator {
		public int compare(Object arg0, Object arg1) {
			return ((Group) arg0).getName().compareTo(((Group) arg1).getName());
		}
	}
	
	private class ResourceVisuComparatorZAxis implements Comparator {
		public int compare(Object arg0, Object arg1) {
			int z1 = ((ResourceVisualization) arg0).getZAxis();
			int z2 = ((ResourceVisualization) arg1).getZAxis();
			if (z1 < z2) return -1;
			if (z1 == z2) return 0;
			else return 1;
		}
	}
}
